Repository navigation
perf(lean,#16031): life_compose caches de trajectoire + hoists byte-equivalents (test_life_compose 19.15s -> 10.1s) - #17347
Conversation
…quivalents (19.15s -> 10.1s) - cells_at/swept_rect memoises par cle de contenu (jamais event_idx), copie fraiche rendue : type et mutabilite observes inchanges - _pair_chebyshev/_window_pair_chebyshev : distance de paire memoisee, la meme paire geometrique etait recontrolee pour chaque candidat - _window_ever_rect : rectangle de fenetre reconstruit par candidat -> cache par (reaction.id, offset) - _extent_grid + compte de gliders hoistes hors des boucles (ne dependent que de state) - certify : clearance scannee avec any() avant tri (hit construit seulement en cas de violation) - run_compositional : tous les caches vids par rep (mesures froides) Preuve byte-equivalence : 8 rapports complets (3 objectifs + 4 ablations + bord TIMEOUT) identiques avant/apres -- verdicts, stats compteur par compteur, temoins. 65 tests passent inchanges (27 life_compose + 38 life_components). Benchmark (meme runner, pytest --durations) : - test_reutilisation_stricte_impossible_borne : 13.24s -> 5.41s (-59%) - test_variante_libre_found : 5.66s -> 3.89s (-31%) - fichier test_life_compose.py : 19.15s -> 10.1s (-47%) Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
|
Rouge Le run 35674498995 (rejeu, complete 2026-09-22T01:55:28Z) rend 14 failed, 14453 passed, 98 skipped, 8 xfailed. Les 14 echecs sont TOUS la classe environnement runner, aucun dans le perimetre de cette PR :
Le runner Corroboration que c'est la base, pas cette PR : les guards du meme commit echouent aussi sur des fetch API CI ( La lane ne revoit pas ces runs (chaque rejeu re-tombe sur le pool degrade) : reparation = cote runner (installer |
|
Rerun des jambes rouges effectue par la lane (04:0xZ) — verdicts : Always-on guards -> success (le rouge perimeter/fastlane etait bien le runner sans gh, corrige par re-routage), Scripts & Notebook-Tools Tests -> failure sur XDIST-WATCHDOG: BLOQUE -- silence de sortie depuis 480 s apres |
|
[Échappatoire non-réparable par la lane — Rouge redocumenté ce cycle avec 2 rejeus supplémentaires (attempts 2 et 3 du run 35674498995), même signature à chaque fois :
La cause est le runner (hang WSL), pas le diff : rien à corriger côté branche, et un push ne changerait rien (re-route non garanti). La réparation qui ferme la classe — router La lane poursuit sa file ; cette candidate attend un |
|
Rouge d'infra runner, pas un defaut du diff — Annotation du job |
|
Diagnostic du rouge Un worker xdist meurt, pytest le remplace, la suite repart (83 -> 89 %) puis le master avorte. Les gardes de plancher de couverture qui suivent ( La classe est deja mesuree dans le workflow lui-meme. L'en-tete de Verification firsthand que le module de la PR est sain (po-2023) :
Contexte de parc, pour situer la classe (issue ouverte ce matin, non claimee) : #17407 documente que deux parcs partagent les labels Geste pris : relance des deux runs en echec ( |
|
[ADJOINT PREFLIGHT] |
Tell c.1392 picker-delivered gap, mesure c.1450-c.1453 (28 cycles successifs sans grain actionnable) : 9/9 candidats verifies LIVREs sur origin/main, dont le label candidate-delivered avait ete retracte par le sweep post-merge (#15744) sans qu'aucune lane ne refute (donc pas de marqueur en commentaire). Le tapis narrow-cache les re-emettait en urne grain faute d'une 3e surface de verification. Cas fondateur : #16031 perf life_compose, PR #17347 MERGED 09/22, label retracte 09/24, servi 28 cycles de suite sans qu'aucune lane ne refute (donc pas de marqueur) -- le sweep post-merge avait supprime le seul signal disponible. Le fix ajoute un 3e predicat dans delivered_signal_reason : - gh pr list --state merged --search 'N in:title,body' --limit 20 - post-filtre ancre #N\b (meme doctrine que open_cover_signal, #17760) -- pas de collision de sous-chaine - post-filtre temporel : mergedAt dans les 90 derniers jours (compromis entre couverture des livraisons recentes et exclusion des PRs historiques) Cout : 1 requete gh par candidat tire, partagee avec le meme plafond DELIVERED_SIGNAL_MAX_PROBES que les 2 autres sondes (commentaire + PR couvrante). Un candidat peut consommer jusqu'a 3 unites de budget. Portee : urne grain SEULE. Les urnes delivered (#15069) et umbrella demeurent inchangees -- la 1re sert precisement ces issues aux lanes habilitees, la 2e n'est jamais ecartee sur un marqueur (un EPIC a un sous-grain a piocher, pas un verdict de fermeture). Tests : 5 nouveaux cas dans test_pick_idle_grain.py : 1. PR MERGEE <90j -> ecarte (controle positif) 2. PR MERGEE >90j -> conserve (fenetre de 90j) 3. pas de PR MERGEE -> conserve (regression preservee) 4. PR MERGEE isolee sans label/marqueur -> ecarte (cas fondateur) 5. ancre #N\b empeche #1170391 de couvrir #11703 (collision sous-chaine, cf #17760) 191/191 tests PASSED (186 precedents + 5 nouveaux), 0 regression. Distinction #19907 vs #19804 (ai-01) : #19907 = urne grain (reemission LIVREs), #19804 = urne fermeture (attribution _manuel). Voies distinctes sur le meme fichier. Co-Authored-By: Claude Haiku 4.5 (1M context) <noreply@anthropic.com>
Tell c.1392 picker-delivered gap, mesure c.1450-c.1453 (28 cycles successifs sans grain actionnable) : 9/9 candidats verifies LIVREs sur origin/main, dont le label candidate-delivered avait ete retracte par le sweep post-merge (#15744) sans qu'aucune lane ne refute (donc pas de marqueur en commentaire). Le tapis narrow-cache les re-emettait en urne grain faute d'une 3e surface de verification. Cas fondateur : #16031 perf life_compose, PR #17347 MERGED 09/22, label retracte 09/24, servi 28 cycles de suite sans qu'aucune lane ne refute (donc pas de marqueur) -- le sweep post-merge avait supprime le seul signal disponible. Le fix ajoute un 3e predicat dans delivered_signal_reason : - gh pr list --state merged --search 'N in:title,body' --limit 20 - post-filtre ancre #N\b (meme doctrine que open_cover_signal, #17760) -- pas de collision de sous-chaine - post-filtre temporel : mergedAt dans les 90 derniers jours (compromis entre couverture des livraisons recentes et exclusion des PRs historiques) Cout : 1 requete gh par candidat tire, partagee avec le meme plafond DELIVERED_SIGNAL_MAX_PROBES que les 2 autres sondes (commentaire + PR couvrante). Un candidat peut consommer jusqu'a 3 unites de budget. Portee : urne grain SEULE. Les urnes delivered (#15069) et umbrella demeurent inchangees -- la 1re sert precisement ces issues aux lanes habilitees, la 2e n'est jamais ecartee sur un marqueur (un EPIC a un sous-grain a piocher, pas un verdict de fermeture). Tests : 5 nouveaux cas dans test_pick_idle_grain.py : 1. PR MERGEE <90j -> ecarte (controle positif) 2. PR MERGEE >90j -> conserve (fenetre de 90j) 3. pas de PR MERGEE -> conserve (regression preservee) 4. PR MERGEE isolee sans label/marqueur -> ecarte (cas fondateur) 5. ancre #N\b empeche #1170391 de couvrir #11703 (collision sous-chaine, cf #17760) 191/191 tests PASSED (186 precedents + 5 nouveaux), 0 regression. Distinction #19907 vs #19804 (ai-01) : #19907 = urne grain (reemission LIVREs), #19804 = urne fermeture (attribution _manuel). Voies distinctes sur le meme fichier. Co-Authored-By: Claude Haiku 4.5 (1M context) <noreply@anthropic.com>
#19913) * fix(picker,#19907): 3e surface de livraison (PR MERGEE <90j) Tell c.1392 picker-delivered gap, mesure c.1450-c.1453 (28 cycles successifs sans grain actionnable) : 9/9 candidats verifies LIVREs sur origin/main, dont le label candidate-delivered avait ete retracte par le sweep post-merge (#15744) sans qu'aucune lane ne refute (donc pas de marqueur en commentaire). Le tapis narrow-cache les re-emettait en urne grain faute d'une 3e surface de verification. Cas fondateur : #16031 perf life_compose, PR #17347 MERGED 09/22, label retracte 09/24, servi 28 cycles de suite sans qu'aucune lane ne refute (donc pas de marqueur) -- le sweep post-merge avait supprime le seul signal disponible. Le fix ajoute un 3e predicat dans delivered_signal_reason : - gh pr list --state merged --search 'N in:title,body' --limit 20 - post-filtre ancre #N\b (meme doctrine que open_cover_signal, #17760) -- pas de collision de sous-chaine - post-filtre temporel : mergedAt dans les 90 derniers jours (compromis entre couverture des livraisons recentes et exclusion des PRs historiques) Cout : 1 requete gh par candidat tire, partagee avec le meme plafond DELIVERED_SIGNAL_MAX_PROBES que les 2 autres sondes (commentaire + PR couvrante). Un candidat peut consommer jusqu'a 3 unites de budget. Portee : urne grain SEULE. Les urnes delivered (#15069) et umbrella demeurent inchangees -- la 1re sert precisement ces issues aux lanes habilitees, la 2e n'est jamais ecartee sur un marqueur (un EPIC a un sous-grain a piocher, pas un verdict de fermeture). Tests : 5 nouveaux cas dans test_pick_idle_grain.py : 1. PR MERGEE <90j -> ecarte (controle positif) 2. PR MERGEE >90j -> conserve (fenetre de 90j) 3. pas de PR MERGEE -> conserve (regression preservee) 4. PR MERGEE isolee sans label/marqueur -> ecarte (cas fondateur) 5. ancre #N\b empeche #1170391 de couvrir #11703 (collision sous-chaine, cf #17760) 191/191 tests PASSED (186 precedents + 5 nouveaux), 0 regression. Distinction #19907 vs #19804 (ai-01) : #19907 = urne grain (reemission LIVREs), #19804 = urne fermeture (attribution _manuel). Voies distinctes sur le meme fichier. Co-Authored-By: Claude Haiku 4.5 (1M context) <noreply@anthropic.com> * fix(picker,#19907): 3 tests belt adaptés à la 3e sonde Les 3 tests belt qui passaient uniquement delivered_probe voient maintenant le 3e probe reel merged_pr_signal s'exécuter, ce qui retourne parfois un signal réel (PRs mergées sur origin/main) et fausse les assertions : - test_belt_withdraws_delivered_candidates_and_replaces excluait 19002 (PR reelle mergee) au lieu de le servir - test_belt_keeps_unmarked_candidate_pickable excluait 19003 - test_belt_unread_probe_is_fail_open_and_reported : budget impacté par la 2e sonde (counted_merged_pr_probe partage le meme budget que counted_probe) Fix : passer merged_pr_probe=lambda n, lane=None: False aux 3 tests pour isoler le scope (le test ne couvre que le label et le marqueur, pas la 3e surface). Re-runs : 3/3 PASSED en 0.16 s. Co-Authored-By: Claude Haiku 4.5 (1M context) <noreply@anthropic.com> * fix(tests,#19913): plafond partage 3 sondes -- budget=4 + merged_pr_probe patch Le test test_plafond_partage_entre_sondes_livraison_et_couverture (test_pick_delivered_gate.py) etait ecrit pour 2 sondes (livraison + couverture). L'ajout du 3e predicat merged_pr_signal par la PR #19913 a partage le budget entre 3 sondes, et la couverture n'etait plus appelee avec le budget=2 d'origine. Fix (commit) : - Plafond 2 -> 4 (2 candidats * 2 sondes couvertes : 1 livraison + 1 merged_pr + 1 cover du 1er candidat, 1 livraison du 2e) - Patcher merged_pr_probe (3e sonde) en counting_merged_pr qui appende dans une liste - Expectations : delivered_calls=[1,2] (2 candidats), merged_pr_calls=[1] (1er candidat, budget epuise avant le 2e), cover_calls=[1] (1er candidat, budget epuise avant le 2e) - Budget hit reste True - len(picks)=2 reste verifie Test : 248/248 PASSED (39 test_pick_delivered_gate + 209 test_pick_idle_grain). Co-Authored-By: Claude Haiku 4.5 (1M context) <noreply@anthropic.com> * fix(tests,#19913): parasite [ et ) du rebase c.1457-L1 (regression de c.1461) Le commit c.1461 (d1e5fdf) a annule silencieusement le fix c.1459 (11510d3) sur test_pick_idle_grain.py : le forced update --force-with-lease a REPLACE le commit precedent au lieu d'etre un fast-forward, et le fix du parasite Tell c.1457-L1 (ligne 3864 [conflit resolu...]) n'etait pas dans le nouveau commit. Le parasite est revenu en production, causant SyntaxError ligne 3864 au job Scripts Tests (CPU) du run 37787241321. 17863 tests sont passes avant le crash de collecte, mais le job est en failure. Fix (re-applique le fix c.1459) : 5 lignes retirees - ligne 3864 : [conflit resolu c.1457 : ...] -> retire (la [ redevenait active comme subscription Python) - ligne 4260 : ) orphelin -> retire Test local : 248/248 PASSED (209 + 39). Regle Tell c.1457-L2 confirmee : commentaire de resolution c.NNNN commence par # Conflit resolu, JAMAIS par [Conflit resolu. Tell c.1455-L1 renforcement : un --force-with-lease sur sa propre branche peut REPLACER un commit anterieur (au lieu d'un fast-forward) et perdre silencieusement des modifications. Le diff de sortie de 'git show' doit etre compare avec le dernier commit avant push. Co-Authored-By: Claude Haiku 4.5 (1M context) <noreply@anthropic.com> * fix(tests,#19913): defauts de sonde inertes + garde anti-gh autouse Le coordinateur a mesure que la suite bloquait sur un subprocess.communicate reel apres fusion avec main (30 s puis >240 s). Trois causes, toutes fermees : 1. belt_pick_with_replacements: defauts = sondes RESEAU (has_delivered_signal, merged_pr_signal). Un test qui oubliait d'injecter sa sonde sortait sur un vrai gh. Defauts passes aux sondes inertes ; main injecte les reelles explicitement (doctrine delivered_probe_inert, deja en vigueur ailleurs). 2. _patch_belt_network enumerait 8 surfaces a la main -- 4 manquaient : pin_gh_token (gh auth token, le VRAI hang : ~300 s par test), fetch_visits, fetch_series_visits, fetch_merged. Enumerer une par une est une course perdue : chaque fonction reseau ajoutee rouvre le trou. 3. Garde autouse `_no_real_gh` module-local : subprocess.run avec gh dans l'argv leve en millisecondes avec la ligne fautive, au lieu de pendre. Derive de BaseException -- le picker attrape large (except Exception) sur ses fetch, un garde qui en deriverait serait avale. Desarmement par @pytest.mark.real_gh (aucun test du fichier n'en a besoin). Deux tests-gardes ajoutes : defauts inertes de la boucle, et chemin complet main --belt --json sans sonde reelle. Mesure : test_pick_idle_grain_belt.py 47 passed en 0,19 s (etait 1182,90 s) ; les 3 fichiers du perimetre 295 passed en 13,49 s. Co-Authored-By: Claude Haiku 4.5 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Haiku 4.5 (1M context) <noreply@anthropic.com>
Grain: MED/refactor — lane myia-po-2023:CoursIA — prev: DEEP/notebook-python #17343
perf(lean,#16031) : caches de trajectoire + hoists byte-équivalents dans
life_compose.py—test_life_compose.py19,15 s → 10,1 s (−47 %). Tranche 6 de #15635, véhicule neuf disjoint de #15863 (tranche 5,life_components.py).Preflight indépendant (acceptance 1) — AVANT toute modification
python -m pytest scripts/lean/tests/test_life_compose.py -q --durations=10sur worktree propre àe8d76767e3(main du 2026-09-22), Python 3.13.3 :test_reutilisation_stricte_impossible_borne13,24 s (69 %) +test_variante_libre_found5,66 s (30 %) — confirme le diagnostic préflight po-2025 (perf(lean,#15635): trajectoire cumulative dans measure_motif — tranche 5 perf #15863 c.1116) : le coût est danslife_compose.py, pas danstest_life_components.py(~0,2 s mesuré ici).Scripts Tests (CPU)de CETTE PR (même classe runner) ; le poste local est mesuré ci-dessus.Diagnostic cProfile (acceptance 2)
python -m cProfile -osur chacun des deux tests dominants, analysepstats:_enumerate_eventsselfcertifycum (dontstep4,48 s)_extent_gridcum (44 800 appels, re-materialisé par combo de phases)cells_atcum (653 k / 1,07 M appels, non mémoïsé)_min_chebyshevcum (paires re-vérifiées à chaque candidat)Causes : (a)
_extent_gridet le compte de gliders ne dépendent que destatemais étaient recalculés par combo de phases/candidat ; (b)cells_atest une fonction pure du contenu mais non mémoïsée — la même paire géométrique est recontrôlée pour chaque candidat suivant ; (c) le rectangle « ever » de fenêtre était reconstruit par candidat dans_surface_oket_spatial_ok; (d) le scan+tri de clearance tournait à chaque pas même sans violation.Modification (1 fichier :
scripts/lean/life_compose.py, +195/−52)_CELLS_AT_CACHE,_SWEPT_RECT_CACHE,_WINDOW_EVER_CACHE,_PAIR_CHEB_CACHE) : clés de contenu (_handle_content_key: motif, ancre, phase, naissance, cellules — jamaisevent_idx), garde de taille 400 k entrées (l'éviction recompute la même valeur), même convention de stabilité parmotif_id/reaction_idque les caches existants_PHASE_OFFSET_CACHE/_WINDOW_CACHE.cells_atrend une copie fraîche : type de retour et mutabilité observés inchangés._pair_chebyshev/_window_pair_chebyshev: distance de paire mémoïsée par contenu — la distance d'une paire au même instant ne peut pas changer entre deux contrôles._enumerate_events:_extent_grid(state)et compte de gliders destatecalculés une fois par énumération (la liste d'offsets est partagée en lecture, jamais mutée) ;spawn_posremplacespawn_slots.index(i)._search: réutilise leconsumedrendu par l'énumérateur (le set était reconstruit dans la condition pour CHAQUE handle vivant).certify: clearance scannée avecany()d'abord — le scan complet + tri ne sert qu'en cas de violation (rare), le contenu de l'entrée produite est inchangé.run_compositional: tous les caches vidés par rep — chaque rep reste la mesure d'une recherche froide, comme_WINDOW_CACHE.test_life_compose.pynon touché.life_components_fixture.jsonnon touché.life_synthesize.py(moteur baseline #15571) non touché.Acceptance stricte — 6 points (analogue #15863)
r1_anchor_collapsed,r2_*,r3_envelope,r4_phase,model_anchor,budget,replay_rejected…) — le hoist_extent_grid/gliders préserve les décomptes carlen(offsets)et les valeurs sommées sont identiques.test_life_compose+ 38test_life_components), tous passent, fichiers de test inchangés.run_compositionalreps=1 :two_blocks,two_blocks_catalyse,two_blocks_catalyse_free, 4 ablations r1–r4, bord TIMEOUTnode_budget=1) dumpés en JSON avant (e8d76767e3) et après (7219b3a497) — diff vide : verdicts, stats compteur par compteur, témoins (12 113 bytes identiques des deux côtés). Les contrôles négatifs (replay falsifié, clearance voyou, budgets serrés, TIMEOUT≠IMPOSSIBLE) passent inchangés.cells_at,swept_rect,certify,Searcher._spatial_okappelé par les tests avec la même signature), comportement d'erreur identique, mêmes verdicts/témoins..github/touché.Scripts Tests (CPU)SUCCESS sous cap 20 min post-merge : attendu sur le run CI de cette PR (même classe runner) puis sur main post-merge — la dissipation du timeout po-2024-linux-docker dépend de la capacité de base (61/61 timeouts, mesure ai-01 c.1116 fin) : cette PR réduit la part du fichier de −47 %, elle ne garantit pas à elle seule la dissipation d'un timeout de capacité.Benchmark avant/après (acceptance 4 — même runner, même commande)
e8d76767e3)7219b3a497)test_reutilisation_stricte_impossible_bornetest_variante_libre_foundpytest scripts/lean/tests/test_life_compose.py(27 tests)test_life_components.py(38 tests, contrôle)Résiduel identifié non consommé (hors scope déclaré) :
step()du moteurlife_synthesize(#15571) ≈ 4,5 s profilés danscertify— toucher le moteur baseline partagé est un véhicule séparé, pas un élargissement silencieux de celle-ci.Anti-régression (CLAUDE.md §D)
Aucune implémentation remplacée par un stub : le diff est additif (caches + hoists), chaque branche de calcul d'origine est conservée sur miss de cache. Insertions (195) > délétions (52), aucune suppression de preuve ni de contrôle négatif.
Scope disjoint (issue #16031)
life_components.py— MERGEDd0a04fd15elife_compose.pyuniquementSee #16031 (acceptance 6 = vérification post-merge par nature : le numéro du run main sera cité en commentaire à l'observation ; fermeture sur cette preuve).
Références
pr_16031_body.md)🤖 Generated with Claude Code